/** 三国战记119
  改装后可以用蹲连了!平a接蹲连的时机需要手动掌握
  撞连也搞定了,方法与蹲连一样但转身没加进去.
  此外还写了爆气时连击的脚本,如关羽的爆气前A
  
  加入了选人密码,兼容115版本
  增加一键道具接连续道具,连续张凌剑的热键
  
  修正了跑动相关参数,测试表明参数应考虑帧的情况,跑动的按下和放开都需要
  2帧,如果手动操作的话,按住方向键会连续发送按下事件,所以多按住一会方向键
  容易正确冲跑.
  
  By setycyas @2024-12-01
*/

/* 全局设定
*/
#Warn
#MaxThreadsPerHotkey 1
SetWorkingDir(A_ScriptDir)
;导入自定义函数库
#Include "..\Class\OrderMap.2.ahk"
#Include "..\Class\MyFuns.2.ahk"
;导入宏相关函数和UI
#Include "..\Class\FaceDetector.2.ahk"
#Include "..\Class\CommonMacro.2.ahk"
#Include "..\Class\CommonUI.2.ahk"
#Include "..\Class\MyEmu.2.ahk"

SendMode("Input")

/* 制作三国战记119的宏类
*/
class KovMacro extends CommonMacro {

  pressDuration := 40

  /* 技能函数 
  */
  
  /* 宏函数
  */
  ;连发需要改装,保证第一下的延迟,否则前冲A容易打不出来!
  _连发A(key){
    local vk
    this._press(1)
    if (this.autoFireDelay == 0){ ;单发
      sleep(100)
      return
    } else {
      vk := GetKeyVk(MyFuns.getHotkey(key))
      loop 3 { ;增加第一发延迟
        if (MyFuns.getVkState(vk)){
          sleep(40)
        } else {
          return
        }
      }
      ; 还按住键则连发,否则停顿一下再中止避免按键太快重新被触发
      if ((!MyFuns.getVkState(vk))){
        sleep(50)
        return
      } else {
        ;继续连发
        super._连发A(key)
      }
    }
  }
  ;连发前一个C保证蹲下后站起,实测表明配合蹲A脚本用于蹲连可行!
  _连发CA(key){
    local vk
    this._down(3)
    this._press(1)
    this._up(3)
    sleep(50)
    vk := GetKeyVk(MyFuns.getHotkey(key))
    if (MyFuns.getVkState(vk)){
      super._连发A(key)
    }else{
      sleep(100)
    }
  }
  ;兼容连击
  _前A(key){
    local face := this._face.face()
    local vk := GetKeyVk(MyFuns.getHotkey(key))
    MyFuns.pressKeys([face, this._keys[1]], [30, 30])
    sleep(50)
    if(MyFuns.getVkState(vk)){
      super._连发A(key)
    }
  }
  _蹲A(key){
    MyFuns.keyDown("down")
    sleep(30)
    this._down(2)
    sleep(30)
    this._up(2)
    MyFuns.keyUp("down")
    sleep(30)
    this._press(1)
    sleep(100)
  }
  ;蹲连参数400十分重要,测试发现对马超张辽诸葛亮都不错
  ;使用方法是连发a之后按住这个快捷键,自动蹲a和CA连发站起攻击
  _蹲连(key){
    MyFuns.keyDown("down")
    sleep(30)
    this._down(2)
    sleep(30)
    this._up(2)
    MyFuns.keyUp("down")
    sleep(30)
    this._press(1)
    sleep(400) ;重要参数
    ;sleep(this.testParams[1]) ;风云用测试,500合适
    if (MyFuns.GetKeyState(key)){
      this._连发CA(key)
    }
  }
  ;经过搜索,发现原来键盘的跑动有时会失败,需要连按三下方向才能保证成功!
  ;处于静止状态时需要先动一下,所以就出现了需要按3次的情况.
  ;用mame插件测试,发现按住方向键只需要1帧,而按键间隔需要2帧!
  ;但实际上不能按住键时间太短,也不能跟mame插件一样快!可能模拟器跟不上,
  ;测试发现按住方向键时间要达到2帧效果才比较好.
  _跑动(key){
    local face, faceDown, faceUP
    face := this._face.face()
    faceDown := "{" . face . " down}" ;为保证速度手动处理
    faceUp := "{" . face . " up}"
    loop 3 {
      send(faceDown)
      sleep(35) 
      send(faceUp)
      sleep(35)
    }
  }
  _下前A(key){
    this._downDown()
    sleep(30)
    this._faceDown()
    sleep(30)
    this._downUp()
    sleep(30)
    this._down(1)
    sleep(30)
    this._faceUp()
    sleep(30)
    this._up(1)
  }
  ;诸葛亮低空万箭穿心,可行但会下移
  _下前BA(key){
    this._downDown()
    sleep(50)
    this._faceDown()
    sleep(40)
    this._downUp()
    sleep(30)
    this._down(2)
    sleep(50)
    this._down(1)
    sleep(30)
    this._faceUp()
    sleep(80)
    this._up(2)
    sleep(30)
    this._up(1)
  }
  ;放手时再次输入a扔出长矛
  _下前A_赵云专用(key){
    static DELAY1 := 700 ;最大放手延迟,超过这个数值不再输入a
    local face := this._face.face()
    local vk ;为保证效率,等一下再赋值
    MyFuns.keyDown("down")
    sleep(30)
    MyFuns.keyDown(face)
    sleep(30)
    MyFuns.keyUp("down")
    sleep(30)
    this._down(1)
    sleep(30)
    MyFuns.keyUp(face)
    sleep(30)
    this._up(1)
    ;等待DELAY1,如放手则直接输入a,否则不再输入并停一下避免重复本热键
    vk := GetKeyVk(MyFuns.getHotkey(key))
    if (MyFuns.waitVkUp(vk, DELAY1, 30)){
      this._press(1)
    }else{
      sleep(500)
    }
  }
  _后前A(key){
    local face := this._face.face()
    local back := this._face.back()
    MyFuns.press(back, 50)
    sleep(50)
    MyFuns.pressKeys([face, this._keys[1]], [30, 30])
  }
  _下上A(key){
    MyFuns.press("down", 50)
    sleep(50)
    MyFuns.pressKeys(["up", this._keys[1]], [30, 30])
  }
  /* 对此热键进行更精确参数优化,有2个发现:
    第一是按住键的时间要长一些,第二是不同场景参数要求差很远
    所以只能用较小的参数,在需要长参数的场景就手动搓招,毕竟手动的时间长
  _下上A(key){
    send("{down down}")
    sleep(this.testParams[1])
    send("{down up}")
    sleep(this.testParams[2])
    send("{up down}")
    sleep(this.testParams[3])
    send("{up up}")
    sleep(this.testParams[4])
    this._down(1)
    sleep(this.testParams[5])
    this._up(1)
  }
  
  */
  _上下A(key){
    MyFuns.press("up", 50)
    sleep(30)
    MyFuns.keyDown("down")
    sleep(30)
    this._down(1)
    sleep(30)
    MyFuns.keyUp("down")
    sleep(30)
    this._up(1)
  }
  _下下A(key){
    send("{down down}")
    sleep(30)
    send("{down up}")
    ;sleep(50)
    sleep(30)
    send("{down down}")
    ;sleep(60)
    sleep(30)
    send("{down up}")
    this._press(1)
    sleep(100)
  }
  ;放手时才松开,兼容赵云超必杀,貂蝉的连击另外设定专用版
  _上下A_赵云专用(key){
    local vk ;为保证效率,等一下再赋值
    MyFuns.press("up", 50)
    sleep(30)
    MyFuns.keyDown("down")
    sleep(30)
    this._down(1)
    sleep(30)
    MyFuns.keyUp("down")
    vk := GetKeyVk(MyFuns.getHotkey(key))
    loop {
      sleep(50)
    } until (!MyFuns.getVkState(vk))
    this._up(1)
  }
  ;貂蝉纵云踢
  _上下A_貂蝉专用(key){
    local vk ;为保证效率,等一下再赋值
    MyFuns.press("up", 50)
    sleep(30)
    MyFuns.keyDown("down")
    sleep(30)
    this._press(1)
    sleep(30)
    MyFuns.keyUp("down")
    sleep(100)
    vk := GetKeyVk(MyFuns.getHotkey(key))
    while(MyFuns.getVkState(vk)){
      this._press(1)
      sleep(70)
    }
  }
  ;追地用
  _追地后前A(key){
    this._down(1)
    sleep(30)
    this._up(1)
    sleep(150)
    this._后前A(key)
  }
  _前前A(key){
    this._跑动(key)
    this._press(1)
  }
  ;反身冲4646,黄忠张飞能用,不按攻击键
  _反身冲4646(key){
    local face, back
    local faceDown, faceUp, backDown, backUp ;为保证速度手动处理按键字符
    local p1, p2 ;测试参数
    face := this._face.face()
    back := this._face.back()
    faceDown := "{" . face . " down}"
    faceUp := "{" . face . " up}"
    backDown := "{" . back . " down}"
    backUp := "{" . back . " up}"
    p1 := 30 ;this.testParams[1]
    p2 := 30 ;this.testParams[2]
    ;4646
    loop 2 {
      send(backDown)
      sleep(p1)
      send(backUp)
      sleep(p2)
      send(faceDown)
      sleep(p1)
      send(faceUp)
      sleep(p2)
    }
    ;this._press(1)
  }
  ;反身冲466,目前诸葛亮赵云能用但速度还是不够快,需要取消平a用否则速度不够
  ;速度太快容易失误所以目前就这参数
  _反身冲466(key){
    local face, back, faceDown, faceUP
    face := this._face.face()
    back := this._face.back()
    faceDown := "{" . face . " down}" ;为保证速度手动处理
    faceUp := "{" . face . " up}"
    MyFuns.keyDown(back)
    sleep(70)
    ;sleep(this.testParams[1])
    MyFuns.keyup(back)
    sleep(35)
    ;sleep(this.testParams[2])
    this._跑动(key)
  }
  ;撞连,平a结束后手动换到这个键,跟蹲连一样.
  ;主要是张飞和黄忠,测试过参数可行
  _撞连(key){
    this._跑动(key)
    this._press(1)
    sleep(100) ;需要测试的关键参数
    if (MyFuns.GetKeyState(key)){
      super._连发A(key)
    }
  }
  ;爆气与爆气时出招,主要是要兼容关羽和赵云的爆气时打浮空
  _爆气(key){
    this._down(5)
    sleep(30)
    this._up(5)
  }
  _爆气前A(key){
    this._爆气(key)
    sleep(50)
    this._前A(key)
  }
  _爆气前A连打(key){
    this._爆气(key)
    sleep(50)
    this._前A(key)
    loop 10 {
      this._down(1)
      sleep(40)
      this._up(1)
      sleep(40)
    }
  }
  ;这招可行,打完微停接下上A即可,再后面不好接的话立即接超必杀
  ;因为这一招打飞敌人不多,反而容易控制,默认用这招.
  _爆气下前A_赵云专用(key){
    this._爆气(key)
    sleep(50)
    this._下前A(key)
    sleep(300)
    this._press(1)
  }
  _爆气下上A(key){
    this._爆气(key)
    sleep(50)
    this._下上A(key)
  }
  ;魔张的两招连接,可中断
  _后前A下前A(key){
    this._后前A(key)
    ;中断判断
    if (MyFuns.waitKeyUp(key, 400)){
      return
    } else {
      this._下前A(key)
      sleep(200)
    }
  }
  ;跳起后立即下A,适用于张辽和白黄的空中最低点攻击
  _空中快速下A(key){
    this._press(2)
    sleep(30)
    MyFuns.keyDown("down")
    sleep(30)
    this._press(1)
    sleep(30)
    MyFuns.keyUp("down")
  }
  ;张飞张辽的爆气连击,原本打算打许褚用,发现不如不爆气直接打...
  _A下前A(key){
    this._press(1)
    sleep(70)
    this._下前A(key)
  }
  ;道具键,按住自动接张凌剑
  _道具键接张凌剑(key){
    local vk
    this._press(4)
    vk := GetKeyVk(MyFuns.getHotkey(key))
    ; 放手立即中断
    loop 3 {
      if (not MyFuns.getVkState(vk)) {
        return
      }
      sleep(30)
    }
    ;只按a的阶段
    loop 15 {
      if (not MyFuns.getVkState(vk)) {
        return
      }
      this._down(1)
      sleep(30)
      this._up(1)
      sleep(40)
    }
    ;ad同按阶段
    while (MyFuns.getVkState(vk)){
      this._down(4)
      this._down(1)
      sleep(30)
      this._up(4)
      this._up(1)
      sleep(40)
    }
  }
  _道具键接连发A(key){
    local vk
    this._press(4)
    vk := GetKeyVk(MyFuns.getHotkey(key))
    ; 放手立即中断
    loop 3 {
      if (not MyFuns.getVkState(vk)) {
        return
      }
      sleep(30)
    }
    ;按a的阶段
    while (MyFuns.getVkState(vk)){
      this._down(1)
      sleep(30)
      this._up(1)
      sleep(40)
    }
  }
  ;选人,简体中文版用
  _选诸葛亮(key){
    static _keys := ["right", "right", this._keys[2], "left", "down", "right", this._keys[3], "left", "up", "right", this._keys[4], "left", "left", this._keys[2]] ;→→B←↓→C←↑→D←←B
    
    for i1, v1 in _keys {
      MyFuns.press(v1)
      sleep(150)
    }
  }
  _选张辽(key){
    static _keys := [this._keys[4], "up", "right", "down", "left", this._keys[2], "left", "down", "right", "up", this._keys[3], "up",  "down", "left", "right"] ;D↑→↓←B←↓→↑C↑↓←→
    
    for i1, v1 in _keys {
      MyFuns.press(v1)
      sleep(50)
    }
  }
  _选貂蝉(key){
    static _keys := ["down", "right", this._keys[4], "up", "down", this._keys[3], this._keys[3], this._keys[3], this._keys[3], "left", "right", this._keys[2], "down", "up"] ;↓→D↑↓CCCC←→B↓↑
    
    for i1, v1 in _keys {
      MyFuns.press(v1)
      sleep(50)
    }
  }
  ;abc和ab
  _AB(key){
    this._press(6)
  }

  /* 重载宏接口
  */
  _setMacro(){
    static obm := ObjBindMethod 
    this.macroMap := OrderMap()
    this.macroMap["空函数"] := obm(this, "_空函数")
    this.macroMap["连发A"] := obm(this, "_连发A")
    this.macroMap["连发CA"] := obm(this, "_连发CA")
    this.macroMap["前A"] := obm(this, "_前A")
    this.macroMap["蹲A"] := obm(this, "_蹲A")
    this.macroMap["蹲连"] := obm(this, "_蹲连")
    this.macroMap["跑动"] := obm(this, "_跑动")
    this.macroMap["下前A"] := obm(this, "_下前A")
    this.macroMap["下前BA"] := obm(this, "_下前BA")
    this.macroMap["下前A_赵云专用"] := obm(this, "_下前A_赵云专用")
    this.macroMap["后前A"] := obm(this, "_后前A")
    this.macroMap["下上A"] := obm(this, "_下上A")
    this.macroMap["上下A"] := obm(this, "_上下A")
    this.macroMap["下下A"] := obm(this, "_下下A")
    this.macroMap["上下A_赵云专用"] := obm(this, "_上下A_赵云专用")
    this.macroMap["上下A_貂蝉专用"] := obm(this, "_上下A_貂蝉专用")
    this.macroMap["追地后前A"] := obm(this, "_追地后前A")
    this.macroMap["前前A"] := obm(this, "_前前A")
    ;this.macroMap["反身冲"] := obm(this, "_反身冲")
    this.macroMap["反身冲466"] := obm(this, "_反身冲466")
    this.macroMap["反身冲4646"] := obm(this, "_反身冲4646")
    this.macroMap["撞连"] := obm(this, "_撞连")
    this.macroMap["爆气"] := obm(this, "_爆气")
    this.macroMap["爆气前A"] := obm(this, "_爆气前A")
    this.macroMap["爆气前A连打"] := obm(this, "_爆气前A连打")
    this.macroMap["爆气下上A"] := obm(this, "_爆气下上A")
    this.macroMap["爆气下前A_赵云专用"] := obm(this, "_爆气下前A_赵云专用")
    this.macroMap["后前A下前A"] := obm(this, "_后前A下前A")
    this.macroMap["空中快速下A"] := obm(this, "_空中快速下A")
    this.macroMap["A下前A"] := obm(this, "_A下前A")
    this.macroMap["道具键接张凌剑"] := obm(this, "_道具键接张凌剑")
    this.macroMap["道具键接连发A"] := obm(this, "_道具键接连发A")
    this.macroMap["选诸葛亮"] := obm(this, "_选诸葛亮")
    this.macroMap["选貂蝉"] := obm(this, "_选貂蝉")
    this.macroMap["选张辽"] := obm(this, "_选张辽")
    this.macroMap["AB"] := obm(this, "_AB")
    this.macroArr := this.macroMap.getKeys()
  }

}

/* 制作三国战记专用UI
*/
class KovUI extends CommonUI {

  DEFAULT_HOTKEYS := "~d,~s,~e,~r,~g,~w"
  HOTKEY_NUM := 8
  EXE_ARRAY := [
    MyEmu.NEBULA_SP2_CPS, MyEmu.FBAS, MyEmu.XZONE, MyEmu.MAME, MyEmu.FBNEO64
  ]

  /* 构造函数
  */
  __New(macro){
    super.__New("三国战记119", macro)
    local p := OrderMap()
    this._preset := p
    p["诸葛亮"] := ["连发A", "前前A", "下前A", "下上A", 
      "蹲连", "道具键接连发A", "选诸葛亮", "爆气"]
    p["张辽"] := ["连发A", "下前A", "后前A", "下上A", 
      "蹲连",  "道具键接连发A", "选张辽", "爆气"]
    p["赵云"] := ["连发A", "下上A", "下前A_赵云专用", "上下A_赵云专用", 
      "前前A", "道具键接连发A", "AB", "爆气下前A_赵云专用"]
    p["关羽"] := ["连发A", "下前A", "前A", "下上A", 
      "跑动",  "道具键接连发A", "AB", "爆气前A"]
    p["真黄忠"] := ["连发A", "下前A", "前A", "上下A", 
      "蹲A", "道具键接连发A", "AB", "爆气"]
    p["马超"] := ["连发A", "前前A", "后前A", "下上A", 
      "蹲连", "道具键接连发A", "AB", "爆气"]
    p["貂蝉"] := ["连发A", "下前A", "上下A_貂蝉专用", "下上A", 
      "蹲A", "道具键接连发A", "AB", "爆气"] 
    p["白张飞"] := ["连发A", "后前A", "下前A", "下上A", 
      "下下A", "道具键接连发A", "AB", "爆气"] ;等级到10可以用撞连
    p["魔张飞"] := ["连发A", "后前A", "下前A", "下下A", 
      "后前A下前A", "道具键接连发A", "AB", "爆气"] ;等级到10可以用撞连
    p["白黄忠"] := ["连发A", "下前A", "前A", "上下A", 
      "反身冲4646", "道具键接连发A", "AB", "爆气"] ;等级到10可以用撞连
  }

  /* 重写接口
  */
  ;首次提交数据,暂时没有准备操作
  /*
  _onSubmitEnd(){
    super._onSubmitEnd()
    if (this._submitTimes == 0){
      HotIfWinActive(this._winTitle)
      Hotkey("RCtrl", this._changeCheatWeapon.bind(this))
      HotIfWinActive()
    }
  }
  */

  /* 重写setup,更改可选的exe,读入预设
  */
  setup(){
    super.setup()
    this._myGui.opt("+AlwaysOnTop")
    this._myGui.show("x1100 y330")
    this.readPresetMenu("白张飞")
  }

}

/* 运行当前脚本
*/
if (A_ScriptName == "三国战记119.2.ahk"){
  face := FaceDetector() ;方向检测对象
  macro := KovMacro(face, ["q", "f", "v", "c", "x"]) ;宏对象,有界面时第二个参数可以随便写但长度不要小于2
  ;新建界面并设定
  ui := KovUI(macro)
  ui.setup()
  ;ui._exeComboBox.Choose(MyEmu.NEBULA_SP2_CPS)
  ui._exeComboBox.Choose(MyEmu.FBNEO64)
  ;ui._gameKeyEdit.Text := "q,f,v,c,x" ;最后一个是爆气键
  ui._gameKeyEdit.Text := "q,d,c,g,i,l" ;最后2个是abc和ab组合键
  ;ui._hotkeyEdit.Text := "~d,s,c,e,r,g"
  ;ui._hotkeyEdit.Text := "~s,~a,~w,~e,~f,~x,~r"
  ui._hotkeyEdit.Text := "~s,~a,~w,~e,~f,~x,~space,~z"
  ui._fpsEdit.Text := 8
  ui._testEdit.Text := "35,35,200,40,40"
  ui.readPresetMenu("诸葛亮")
}